//
//  String+YYLib.swift
//  SwiftProject
//
//  Created by yangyuan on 2018/1/11.
//  Copyright © 2018年 huan. All rights reserved.
//

///https://www.cnblogs.com/zhuzi1995/p/7653685.html
/// 用的时候可以直接import Darwin, 不过这个Module 已经存在与UIKit里面了，所以有import UIKit，就不必再import Darwin，而如果没有import UIKit的话，输入arc三个字母进行测试发现函数出不来，这时候就要在前面加上import Darwin。
#if os(Linux)
import SwiftGlibc

public func arc4random_uniform(_ max: UInt32) -> Int32 {
  return (SwiftGlibc.rand() % Int32(max-1))
}
#endif

import Foundation

#if canImport(UIKit)
import UIKit
#endif

#if canImport(Cocoa)
import Cocoa
#endif

#if canImport(CoreGraphics)
import CoreGraphics
#endif

// MARK: - Subscript
public extension String {
	/// Safely subscript string with index.
	///
	///		"Hello World!"[3] -> "l"
	///		"Hello World!"[20] -> nil
	///
	/// - Parameter i: index.
	subscript(safe i: Int) -> Character? {
		guard i >= 0 && i < count else { return nil }
		return self[index(startIndex, offsetBy: i)]
	}
	
	/// Safely subscript string within a half-open range.
	///
	///		"Hello World!"[6..<11] -> "World"
	///		"Hello World!"[21..<110] -> nil
	///
	/// - Parameter range: Half-open range.
	subscript(range: CountableRange<Int>) -> String? {
		guard
			let lowerIndex = index(startIndex, offsetBy: max(0, range.lowerBound), limitedBy: endIndex),
			let upperIndex = index(lowerIndex, offsetBy: range.upperBound - range.lowerBound, limitedBy: endIndex) else {
				return nil
		}
		return String(self[lowerIndex..<upperIndex])
	}
	
	/// Safely subscript string within a closed range.
	///
	///		"Hello World!"[6...11] -> "World!"
	///		"Hello World!"[21...110] -> nil
	///
	/// - Parameter range: Closed range.
	subscript(range: ClosedRange<Int>) -> String? {
		guard
			let lowerIndex = index(startIndex, offsetBy: max(0, range.lowerBound), limitedBy: endIndex),
			let upperIndex = index(lowerIndex, offsetBy: range.upperBound - range.lowerBound + 1, limitedBy: endIndex) else {
				return nil
		}
		return String(self[lowerIndex..<upperIndex])
	}
	
	/// EZSE: Cut string from integerIndex to the end
	subscript(integerIndex: Int) -> Character {
		let idx = index(startIndex, offsetBy: integerIndex)
		return self[idx]
	}
}

extension String {
    func toURL() -> URL? {
        return URL(string: self)
    }
    
    func toFileURL() -> URL {
        return URL(fileURLWithPath: self)
    }
    
    func removingPrefix(_ prefix: String) -> String {
        guard hasPrefix(prefix) else { return self}
        return String(dropFirst(prefix.count))
    }
    
    /// SwifterSwift: Removes given suffix from the string.
    ///
    ///   "Hello, World!".removingSuffix(", World!") -> "Hello"
    ///
    /// - Parameter suffix: Suffix to remove from the string.
    /// - Returns: The string after suffix removing.
    func removingSuffix(_ suffix: String) -> String {
        guard hasSuffix(suffix) else { return self }
        return String(dropLast(suffix.count))
    }
}


// MARK: - 编码相关
public extension String {
	/// URL escaped string.
	///
	///		"it's easy to encode strings".urlEncoded -> "it's%20easy%20to%20encode%20strings"
	///
	func urlEncoded(characterSet: CharacterSet = .urlHostAllowed) -> String {
		return addingPercentEncoding(withAllowedCharacters: characterSet) ?? self
	}
	
	/// Readable string from a URL string.
	///
	///		"it's%20easy%20to%20decode%20strings".urlDecoded -> "it's easy to decode strings"
	///
	func urlDecoded() -> String {
		return removingPercentEncoding ?? self
	}
	
	/// String encoded in base64 (if applicable).
	///
	///		"Hello World!".base64Encoded() -> Optional("SGVsbG8gV29ybGQh")
	///
	func base64Encoded(options: Data.Base64EncodingOptions = .lineLength64Characters) -> String {
		return Data(utf8).base64EncodedString(options: options)
	}
	
	/// String decoded from base64 (if applicable).
	///
	///		"SGVsbG8gV29ybGQh".base64Decoded() = Optional("Hello World!")
	///
	func base64Decoded(encoding: String.Encoding = .utf8) -> String? {
		return base64DecodedData().flatMap { String(data: $0, encoding: encoding) }
	}
	
	func base64EncodedData(options: Data.Base64EncodingOptions = .lineLength64Characters) -> Data? {
		return data(using: .utf8).flatMap { $0.base64EncodedData(options: options) }
	}
	
	func base64DecodedData(options: NSData.Base64DecodingOptions = .ignoreUnknownCharacters) -> Data? {
		return Data(base64Encoded: self, options: options)
	}
	
	func unicodeString() -> String? {
		guard let cString = cString(using: .nonLossyASCII) else {
			return nil
		}
		return String(cString: cString, encoding: .utf8)
	}
	
	func deUnicodeString() -> String? {
		guard let cString = cString(using: .utf8) else {
			return nil
		}
		return String(cString: cString, encoding: .nonLossyASCII)
	}
	
	var md5: String{
		return self
	}
}

// MARK: - Convert String
public extension String {
	/// String with no spaces or new lines in beginning and end.
	///
	///		"   hello  \n".trimmed -> "hello"
	///
	var trimmed: String {
		return trimmingCharacters(in: .whitespacesAndNewlines)
	}
	
	mutating func trim() {
		self = trimmed
	}
	
	/// String without spaces and new lines.
	///
	///		"   \n Swifter   \n  Swift  ".withoutBlank -> "SwifterSwift"
	///
	var withoutBlank: String {
		return replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "")
	}
	
	/// Reverse string.
	var reversedString: String {
		return String(reversed())
	}
	
	mutating func reverse() {
		self = reversedString
	}
}



// MARK: - Operators
public extension String {
	/// Repeat string multiple times.
	///
	///		'bar' * 3 -> "barbarbar"
	///
	/// - Parameters:
	///   - lhs: string to repeat.
	///   - rhs: number of times to repeat character.
	/// - Returns: new string with given string repeated n times.
	static func *(lhs: String, rhs: Int) -> String {
		guard rhs > 0 else { return "" }
		return String(repeating: lhs, count: rhs)
	}
	
	/// Repeat string multiple times.
	///
	///		3 * 'bar' -> "barbarbar"
	///
	/// - Parameters:
	///   - lhs: number of times to repeat character.
	///   - rhs: string to repeat.
	/// - Returns: new string with given string repeated n times.
	static func * (lhs: Int, rhs: String) -> String {
		guard lhs > 0 else { return "" }
		return String(repeating: rhs, count: lhs)
	}
}

// MARK: - NSString extensions
public extension String {
    /// NSString from a string.
    var nsString: NSString {
        return self as NSString
//        return NSString(string: self)
    }
    
    /// NSString lastPathComponent.
    var lastPathComponent: String {
        return (self as NSString).lastPathComponent
    }
    
    /// NSString pathExtension.
    var pathExtension: String {
        return (self as NSString).pathExtension
    }
    
    /// NSString deletingLastPathComponent.
    var deletingLastPathComponent: String {
        return (self as NSString).deletingLastPathComponent
    }
    
    /// NSString deletingPathExtension.
    var deletingPathExtension: String {
        return (self as NSString).deletingPathExtension
    }
    
    /// NSString pathComponents.
    var pathComponents: [String] {
        return components(separatedBy: "/")
    }
    
    /// NSString appendingPathComponent(str: String)
    ///
    /// - Parameter str: the path component to append to the receiver.
    /// - Returns: a new string made by appending aString to the receiver, preceded if necessary by a path separator.
    func appendingPathComponent(_ str: String) -> String {
        return (self as NSString).appendingPathComponent(str)
    }
    
    /// NSString appendingPathExtension(str: String)
    ///
    /// - Parameter str: The extension to append to the receiver.
    /// - Returns: a new string made by appending to the receiver an extension separator followed by ext (if applicable).
    func appendingPathExtension(_ str: String) -> String {
        return (self as NSString).appendingPathExtension(str) ?? self
    }
    /*
    /Users/caoxu/Documents
    
    /Users/caoxu/Documents/test            appendingPathComponent(test)
    /Users/caoxu/Documents/test.plist     appendingPathExtension(plist)
    */
}













